package lzupdater.com;

import java.util.ArrayList;

import lzupdater.locale.LocalizedString;

//LZRosterUpdater, a java client to update LZRoster
//Copyright (C) 2008 Fraskor from Krasus (e-mail: fraskor@gmail.com)
//
//This file is part of LZRosterUpdater.
//
//LZRosterUpdater is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Hub to which component can be registered and retreive. The component are
 * defined by their class type. This hub can be seen as a singleton manager.
 * 
 * @author Fraskor
 */
public class CommunicationHub {

	private LocalizedString componentAlreadyRegistered = new LocalizedString(
			"The component '%s' is already registered");

	private ArrayList<HubElement<HubComponent>> components = new ArrayList<HubElement<HubComponent>>();
	private ArrayList<HubComponent> listeners = new ArrayList<HubComponent>();

	/**
	 * Add an element to the hub
	 * 
	 * @param <T>
	 *            the type of the element
	 * @param element
	 *            the element to add
	 * @return the element itself
	 */
	public <T extends HubComponent> T add(T element) {
		this.addComponent(element);
		listeners.add(element);
		return element;
	}

	/**
	 * Retrieve a component of a specified application from the central
	 * 
	 * @param <T>
	 *            the type of the component to retreive
	 * @param classId
	 *            the class type of the component
	 * @return the component of type T if registered, else throw an exception
	 */
	@SuppressWarnings("unchecked")
	public <T extends HubComponent> T getComponent(Class<T> classId) {
		for (HubElement<HubComponent> c : components) {
			if (c.classId.equals(classId))
				return (T) c.component;
		}
		throw new RuntimeException("Could not get the component "
				+ classId.getSimpleName());

	}

	/**
	 * Call the method 'initializeCommunication' for each registered components
	 * and then the method 'initialize' again for each registered components
	 */
	public void initialize() {
		for (HubComponent l : listeners) {
			l.initializeCommunication();
		}
		for (HubComponent l : listeners) {
			l.initialize();
		}
	}

	private <T extends HubComponent> T addComponent(T component) {
		HubElement<HubComponent> tmp = new HubElement<HubComponent>(component);

		if (components.contains(tmp)) {
			throw new IllegalArgumentException(String
					.format(componentAlreadyRegistered.toString(), component
							.getClass()));
		}
		components.add(tmp);
		return component;
	}

	/**
	 * Internal class containing the registered component and it class type
	 * 
	 * @author Fraskor
	 * @param <T>
	 *            type of the component
	 */
	private static class HubElement<T extends HubComponent> {
		private final Class<?> classId;
		private final T component;

		public HubElement(T component) {
			this.classId = component.getClass();
			this.component = component;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		@Override
		public boolean equals(Object obj) {
			return this.classId.equals(obj);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#hashCode()
		 */
		@Override
		public int hashCode() {
			return this.classId.hashCode();
		}

	}

}
